-module(gs_test).

-compile(export_all).


%%%  TEST GRAPH 1
%%%
%%%  


%% tg1 describes the graph on p98 of Luger & Stubblefield.
tg1(a) ->
    [b, c, d];
tg1(b) ->
    [e, f];
tg1(c) ->
    [f, g];
tg1(d) ->
    [];
tg1(e) ->
    [h, i];
tg1(f) ->
    [j];
tg1(g) ->
    [];
tg1(h) ->
    [];
tg1(i) ->
    [];
tg1(j) ->
    [].


%% Make a simple function which will return true when given Node
%% and false otherwise.
make_goal(Node) ->
    fun (X) when X == Node -> true;
        (_) -> false
    end.


%% Test tg1 to find GoalNode and return either the path from the
%% root ('a') to GoalNode or else fail.
test_graph(GoalNode) ->
    graph_search:backtrack(
      a, 
      make_goal(GoalNode), 
      fun tg1/1, 
      fun graph_search:full_log/5
      %%fun (fwd, A, B, C, D) -> graph_search:full_log(fwd, A, B, C, D);
      %%    (_, _, _, _, _) -> ok 
      %%end
     ). 


test_strategy(GN, dfs) ->
    test_strategy(GN, depth_first);
test_strategy(GN, bfs) ->
    test_strategy(GN, breadth_first);
test_strategy(GoalNode, Mode) ->
    graph_search:Mode(
      a,
      make_goal(GoalNode),
      fun tg1/1
     ).


%%% 
%%%  AND NOW, LADEEZ AND GENNULMEN, THE INFAMOUS
%%%  "GOAT, CABBAGE, WOLF & RIVER PROBLEM" ...
%%%
%%%
%%%  Note that you can't solve the GCWR problem with
%%%  any of the naive searches we currently have.  We
%%%  will need to add something to backtrack such that 
%%%  it tests a given state to figure out if it's a
%%%  failure and then kick of backtracking.  This, in
%%%  and of itself, will be a step on the road to Prolog.
%%%

-record(river, {start=[], end=[], boat_at}).


river_goal(#river{start=[], end=All}) when length(All) == 3 ->
    true;
river_goal(#river{}) -> 
    false.


river_start() ->
    #river{start=[goat, cabbage, wolf], end=[], boat_at=start}.


eats(goat, cabbage) ->
    true;
eats(wolf, goat) ->
    true;
eats(_, _) ->
    false.


eats_any(Eater, [Thing|Rest]) ->
    case eats(Eater, Thing) of
        true -> true;
        false -> eats_any(Eater, Rest)
    end;
eats_any(Eater, []) ->
    false.
            

bank_is_safe([Inhabitant|Others], PossibleFood) ->
    case eats_any(Inhabitant, PossibleFood) of
        true -> false;
        false -> bank_is_safe(Others, PossibleFood)
    end;
bank_is_safe([], _) ->
    true.


bank_is_safe(Bank) when is_list(Bank) ->
    bank_is_safe(Bank, Bank).


banks_are_safe(#river{left=LBank, right=RBank}) ->
    bank_is_safe(LBank) andalso bank_is_safe(RBank).
